home *** CD-ROM | disk | FTP | other *** search
/ Collection of Tools & Utilities / Collection of Tools and Utilities.iso / asmutil / asm_n_z.zip / SIEVE386.ASM < prev    next >
Assembly Source File  |  1987-04-03  |  7KB  |  261 lines

  1.     title    'Eratosthenes Sieve for 80386'
  2.     name    sieve
  3.     page    50,132
  4.  
  5. ;
  6. ; Eratosthenes Sieve for 80386 32-bit protected mode
  7. ; Implemented by Ray Duncan, April 1987
  8. ; After Gilbreath, Byte September 1981, and January 1983
  9. ;
  10. ; Here is the MAKE file for this program:
  11. ;
  12. ; sieve386.obj : sieve386.asm
  13. ;   386asm sieve386
  14. ; sieve386.exe : sieve386.obj
  15. ;   386link sieve386 start386 -exe sieve386 -map sieve386
  16. ;
  17. ; To run the program with PharLap DOS|EXTENDER:
  18. ;   C>RUN386 SIEVE386
  19. ;
  20.  
  21. niter    equ     100              ; number of iterations
  22. asize   equ     8190            ; size of array "flags"
  23.  
  24. cr    equ    0dh            ; ASCII carriage return
  25. lf    equ    0ah            ; ASCII line feed
  26.  
  27. stdin    equ     0            ; handle for standard input
  28. stdout    equ    1            ; handle for standard output
  29.  
  30.  
  31. _TEXT    segment para public use32 'CODE'
  32.  
  33.     assume cs:_TEXT,ds:_DATA,es:_DATA
  34.  
  35.     public _start_            ; magic name for RUN386 entry
  36.  
  37. _start_    proc    near
  38.  
  39.     xor    edx,edx            ; convert number of iterations
  40.     mov    eax,niter        ; for output
  41.     mov    ecx,10
  42.     mov    esi,offset msg1a+3
  43.     call    binasc
  44.  
  45.     mov    edx,offset msg1        ; display message
  46.     mov    ecx,msg1_len        ; "Starting N iterations of sieve"
  47.     call    pmsg
  48.  
  49.     call    getmsec            ; get current time in msec
  50.     push    eax            ; and save it...
  51.  
  52.         mov     counter,niter        ; initialize iterations counter
  53.  
  54. sieve1:                    ; a sieve iteration starts here...
  55.     mov    edi,offset flags    ; initialize flags array
  56.     mov    ecx,asize        ; to all bytes = TRUE
  57.     mov    al,1
  58.     cld
  59.     rep stosb
  60.  
  61.      xor    esi,esi            ; ESI = index to flags array
  62.     xor    edi,edi            ; EDI = primes counter
  63.  
  64. sieve2:                     ; main loop of sieve
  65.         test    byte ptr flags[esi],1    ; is this a prime?
  66.     jnz    short sieve4        ; jump if prime
  67.  
  68. sieve3:    inc     esi            ; bump to next slot in "flags"
  69.     cmp    esi,asize
  70.     jle    sieve2            ; loop until array exhausted
  71.  
  72.     dec    counter            ; count off sieve iterations
  73.     jnz    sieve1            ; jump, another iteration needed.
  74.     jmp    sieve7            ; jump, all iterations finished.
  75.  
  76. sieve4:                    ; prime found, zap its multiples
  77.     mov    ebx,esi            ; copy i
  78.      mov     edx,ebx         ; EDX = prime = i + i + 3
  79.         add    edx,edx
  80.         add     edx,3
  81.     xor    al,al
  82.     jmp    short sieve6
  83.  
  84. sieve5:    mov    byte ptr flags[ebx],al    ; zero this multiple
  85.  
  86. sieve6:    add     ebx,edx            ; find next multiple of prime
  87.         cmp     ebx,asize        ; have we exhausted the array?
  88.         jle    sieve5            ; not yet, zap it
  89.     inc     edi            ; count primes and try next
  90.     jmp    sieve3
  91.  
  92. sieve7:    call    getmsec            ; all done, get current time
  93.     push    eax
  94.  
  95.     mov    eax,edi            ; convert number of primes 
  96.     mov    edx,0            ; found on last iteration
  97.     mov    ecx,10
  98.     mov    esi,offset msg2a+4
  99.     call    binasc
  100.  
  101.     mov    edx,offset msg2        ; display "Number of primes: "
  102.     mov    ecx,msg2_len
  103.     call    pmsg
  104.  
  105.     pop    eax            ; calculate total elapsed msec.
  106.     pop    ebx
  107.     sub    eax,ebx
  108.  
  109.     mov    edx,0            ; divide by number of iterations
  110.     mov    ecx,niter        ; to get msec per iteration
  111.     idiv    ecx
  112.  
  113.     mov    edx,0            ; convert msec to ASCII
  114.     mov    ecx,10
  115.     mov    esi,offset msg3a+4
  116.     call    binasc
  117.  
  118.     mov    edx,offset msg3        ; display "Elapsed time:"
  119.     mov    ecx,msg3_len
  120.     call    pmsg
  121.  
  122.      mov     ax,04C00h        ; final exit, return code = 0 
  123.         int     21H
  124.  
  125. _start_    endp
  126.  
  127.  
  128. getmsec    proc    near            ; Return EAX = current time in msec.
  129.  
  130.     mov    ah,2ch            ; read time    
  131.     int    21h
  132.     movzx    eax,ch            ; EAX := hours
  133.     imul    eax,60            ; hours -> minutes
  134.     and    ecx,0ffh        ; isolate system minutes
  135.     add    eax,ecx            ; and find total minutes
  136.     imul    eax,60            ; minutes -> seconds
  137.     movzx    ecx,dh            ; isolate system seconds
  138.     add    eax,ecx            ; and find total seconds
  139.     and    edx,0ffh        ; isolate hundredths
  140.     imul    eax,100            ; seconds -> hundredths
  141.     add    eax,edx            ; find total hundredths
  142.     imul    eax,10            ; hundredths -> msec
  143.     ret
  144.  
  145. getmsec    endp
  146.  
  147. ;
  148. ; BINASC: Convert 64 bit binary value to ASCII string.
  149. ;
  150. ; Call with  EDX:EAX  = signed 64 bit value
  151. ;         ECX      = radix
  152. ;            DS:ESI   = last byte of area to store resulting string
  153. ;                    (make sure enough room is available to store
  154. ;                the string in the radix you have selected.)
  155. ;
  156. ; Destroys EAX, EBX, ECX, EDX, and ESI.
  157. ;
  158. binasc     proc    near            ; convert EDX:EAX to ASCII.
  159.  
  160.     mov    byte ptr [esi],'0'     ; force storage of at least 1 digit.
  161.     or    edx,edx            ; test sign of 64 bit value,
  162.     pushf                ; and save sign on stack.
  163.     jns    bin1            ; jump if it was positive.
  164.     not    edx            ; negative, take 2's complement
  165.     not    eax            ; of the value. 
  166.     add    eax,1
  167.     adc    edx,0
  168. bin1:                    ; divide 64 bit value by the radix 
  169.                     ; to extract next digit for the
  170.                     ; forming string.
  171.     mov    ebx,eax            ; is the value zero yet?
  172.     or    ebx,edx
  173.     jz    bin3            ; yes, we are done converting.
  174.     call    divide            ; no, divide by radix.
  175.     add    bl,'0'            ; convert remainder to ASCII digit.
  176.     cmp    bl,'9'            ; might be converting hex ASCII,
  177.     jle    bin2            ; jump if in range 0-9,
  178.     add    bl,'A'-'9'-1        ; correct it if in range A-F.
  179. bin2:    mov    [esi],bl        ; store this character into string.
  180.     dec    esi            ; back up through string,
  181.     jmp    bin1            ; and do it again.
  182. bin3:                    ; restore sign flag,
  183.     popf                ; was original value negative?
  184.     jns    bin4            ; no, jump
  185.     mov    byte ptr [esi],'-'    ; yes,store sign into output string.
  186. bin4:    ret                ; back to caller.
  187.  
  188. binasc    endp
  189.  
  190. ;
  191. ; General purpose 64 bit by 32 bit unsigned divide.
  192. ; This must be used instead of the plain machine unsigned divide
  193. ; for cases where the quotient may overflow 32 bits.  If called with
  194. ; zero divisor, this routine returns the dividend unchanged and gives 
  195. ; no warning.
  196. ;
  197. ; Call with EDX:EAX = 64 bit dividend
  198. ;           ECX     = divisor
  199. ;
  200. ; Returns   EDX:EAX = quotient
  201. ;           EBX     = remainder
  202. ;        ECX     = divisor (unchanged)
  203. ;
  204. divide    proc    near            ; Divide EDX:EAX by ECX
  205.  
  206.     jecxz    div1            ; exit if divide by zero
  207.     push    eax            ; 0:dividend_upper/divisor
  208.     mov    eax,edx
  209.     xor    edx,edx
  210.     div    ecx
  211.     mov    ebx,eax            ; EBX = quotient1
  212.     pop    eax            ; remainder1:dividend_lower/divisor
  213.     div    ecx
  214.     xchg    ebx,edx            ; EDX:EAX = quotient1:quotient2
  215.  
  216. div1:    ret                ; EBX = remainder2
  217.  
  218. divide    endp
  219.  
  220.  
  221. pmsg    proc    near            ; print a message on std output
  222.                     ; call with DS:EDX = address 
  223.                     ;           ECX    = length 
  224.     mov    ah,40h
  225.     mov    bx,stdout
  226.     int    21h
  227.     ret
  228. pmsg    endp
  229.  
  230. _TEXT    ends
  231.  
  232.  
  233. _DATA    segment para public use32 'DATA'
  234.  
  235.  
  236. flags    db      asize+1 dup (?)
  237. counter    dd      ?            ; sieve iteration counter
  238.  
  239. msg1    db    cr,lf,'Starting '
  240. msg1a    db    '     iterations of Sieve...',cr,lf
  241. msg1_len equ $-msg1
  242.  
  243. msg2    db    cr,lf,'Primes found:  '
  244. msg2a    db    '     ',cr,lf
  245. msg2_len equ $-msg2
  246.  
  247. msg3    db    cr,lf,'Elapsed time:  '
  248. msg3a    db    '       msec. per iteration',cr,lf
  249. msg3_len equ $-msg3
  250.     
  251.  
  252. _DATA    ends
  253.  
  254.  
  255. _STACK    segment byte stack use32 'stack'
  256.           db      4096 dup (?)
  257. _STACK    ends
  258.  
  259.     end
  260.